/*
 * Copyright 2009 Original Author(s)
 * 
 * This file is part of Kommando
 * 
 * Kommando is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Kommando is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Kommando.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kommando.core.controlcenter;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.event.ListEvent;
import ca.odell.glazedlists.event.ListEventListener;

import net.miginfocom.swing.MigLayout;

/**
 * @author Peter De Bruycker
 */
public class PreferenceDialog extends ApplicationDialog {

    private List<PreferencePage> pages = new ArrayList<PreferencePage>();
    private JPanel pageHolder;
    private JLabel titleLabel;
    private JTree pagesTree;
    private PreferencePageTreeModel treeModel;

    public PreferenceDialog(Window parent) {
        super(parent, "Preferences");
    }

    @Override
    protected JComponent createDialogContent() {
        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        splitPane.setDividerLocation(100);
        splitPane.setDividerSize(2);
        splitPane.setBorder(null);

        JPanel leftPanel = new JPanel(new MigLayout("", "0[grow]0", "0[grow]0"));

        treeModel = new PreferencePageTreeModel();
        treeModel.setPages(pages);
        pagesTree = new JTree(treeModel);
        pagesTree.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        pagesTree.setShowsRootHandles(true);
        pagesTree.setRootVisible(false);
        pagesTree.setCellRenderer(new DefaultTreeCellRenderer() {
            @Override
            public Component getTreeCellRendererComponent(JTree tree, Object value, boolean arg2, boolean arg3,
                    boolean arg4, int arg5, boolean arg6) {
                super.getTreeCellRendererComponent(tree, value, arg2, arg3, arg4, arg5, arg6);

                if (value != null) {
                    PreferencePage page = (PreferencePage) value;
                    setText(page.getName());
                    setIcon(null);
                }

                return this;
            }
        });
        pagesTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        pagesTree.addTreeSelectionListener(new TreeSelectionListener() {
            private TreePath previous = null;

            @Override
            public void valueChanged(TreeSelectionEvent e) {
                TreePath path = e.getPath();

                if (path.getPathCount() == 0) {
                    pagesTree.setSelectionPath(previous);
                } else {
                    previous = path;
                    pageSelected((PreferencePage) path.getLastPathComponent());
                }
            }
        });

        JScrollPane scrollPane = new JScrollPane(pagesTree);
        scrollPane.setBorder(null);

        leftPanel.add(scrollPane, "grow");

        JPanel rightPanel = new JPanel(new MigLayout("wrap 1", "0[grow]0", "0[]0[]0[grow][]"));
        titleLabel = new JLabel("title");
        titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, titleLabel.getFont().getSize2D() * 1.2f));
        titleLabel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        rightPanel.add(titleLabel, "growx");
        rightPanel.add(new JSeparator(JSeparator.HORIZONTAL), "growx");

        pageHolder = new JPanel(new BorderLayout());
        rightPanel.add(pageHolder, "grow");

        rightPanel.add(new JButton(restoreDefaultsAction), "tag right, split");
        rightPanel.add(new JButton(applyAction), "tag right, split, gapright r");

        splitPane.setLeftComponent(leftPanel);
        splitPane.setRightComponent(rightPanel);

        Dimension maximumPageSize = new Dimension(400, 250);
        for (PreferencePage page : pages) {
            Dimension pageSize = page.getComponent().getPreferredSize();

            maximumPageSize.width = Math.max(pageSize.width, maximumPageSize.width);
            maximumPageSize.height = Math.max(pageSize.height, maximumPageSize.height);
        }

        pageHolder.setPreferredSize(maximumPageSize);

        pagesTree.setSelectionRow(0);

        return splitPane;
    }

    private PreferencePage getSelectedPage() {
        return (PreferencePage) pagesTree.getSelectionPath().getLastPathComponent();
    }

    private Action restoreDefaultsAction = new AbstractAction() {
        {
            putValue(MNEMONIC_KEY, (int) 'd');
            putValue(NAME, "Restore Defaults");
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            PreferencePage page = getSelectedPage();
            if (page != null) {
                page.restoreDefaults();
            }
        }
    };

    private Action applyAction = new AbstractAction() {
        {
            putValue(MNEMONIC_KEY, (int) 'a');
            putValue(NAME, "Apply");
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            PreferencePage page = getSelectedPage();
            if (page != null) {
                page.apply();
            }
        }
    };

    @Override
    protected void onCancel() {
    }

    @Override
    protected boolean onFinish() {
        boolean success = true;

        for (PreferencePage page : pages) {
            if (!page.apply()) {
                // TODO go to page that didn't get applied, show warning/error to user
                success = false;
            }
        }

        return success;
    }

    protected void pageSelected(PreferencePage page) {
        pageHolder.removeAll();
        titleLabel.setText(" ");

        if (page != null) {
            titleLabel.setText(page.getName());
            pageHolder.add(page.getComponent());
            pageHolder.revalidate();
            pageHolder.repaint();
        }
    }

    public void setPages(final EventList<PreferencePage> pages) {
        this.pages = pages;
        pages.addListEventListener(new ListEventListener<PreferencePage>() {
            @Override
            public void listChanged(ListEvent<PreferencePage> arg0) {
                treeModel.setPages(pages);
            }
        });
    }
}
